# @Time : 2020/7/11 11:19
# @Author : Fioman 
# @Phone : 13149920
import math
from array import array
import reprlib


class Vector2d(object):
    typcode = 'd'  # 1.typecode是类属性,在Vector2d实例和直接序列之间转换时使用.

    def __init__(self, components):  # 在__init__方法中把x和y转换成浮点数,尽早捕获错误,以防止调用Vector2d函数时传入不当参数
        self._components = array(self.typcode, components)

    def __iter__(self):  # 定义__iter__方法,把Vector2d实例变成可迭代对象,这样才能拆包(例如,x,y = my_vector).这个方法的实现方式很简单,
        # 直接调用生成器表达式一个接一个产出分量.
        return iter(self._components)

    def __repr__(self):  # 4. __repr__方法使用{!r}获取各个分量的表示形式,然后插值,构成一个字符串;因为Vector2d实例时可迭代对象,所以*self会把x和y分量供给format函数
        components = reprlib.repr(self._components)
        components = components[components.find("["):-1]
        return "Vector({})".format(components)

    def __str__(self):  # 从可迭代的vector2d中轻松获取一个元组,显示为一个序列
        return str(tuple(self))

    def __bytes__(self):  # 为了生成字节序列,我们把typecode转换成字节序列,然后..........
        return (bytes([ord(self.typcode)]) + bytes(self._components))  # 7.迭代Vector2d实例,得到一个数组,再把数组转换成字节序列.

    def __eq__(self, other):  # 为了尽快的比较所有分量,在操作数中构建元组.对Vector2d实例来说,可以这样做,不过仍然有问题.
        return tuple(self) == tuple(other)

    def __abs__(self):  # 模式x和y分量构成的直角三角形的斜边长
        return math.sqrt(sum(x * x for x in self))

    def __bool__(self):  # __bool__方法使用abs(self)计算模,然后把结构转换成bool值.因此0.0是False,非零值是True
        return bool(abs(self))

    def __len__(self):
        return len(self._components)

    def __getitem__(self, index):
        return self._components[index]

    # 我们可以把Vector3d实例转换成字节序列了;同理,也应该能从字节序列转换成Vector2d实例.
    @classmethod
    def frombytes(cls, octets):
        typecode = chr(octets[0])  # 从第一个字节中读取typecode
        memv = memoryview(octets[1:]).cast(typecode)  # 使用传入的octets字节序列创建一个memoryview,然后使用typecode转换.
        return cls(*memv)  # 拆包转换后的memoryview,得到一个构造方法所需要的一对参数.


if __name__ == '__main__':
    v1 = Vector2d([3,4,5])
    print("len(v1) = {}".format(len(v1)))
    print("v1(0) = {},v1(-1) = {}".format(v1[0],v1[-1]))

    v7 = Vector2d(range(7))
    print("v7[1:4] = {}".format(v7[1:4]))
